﻿// -------------------------------------------------------------------------
//    @FileName         :    NFSecurity.cpp
//    @Author           :    gaoyi
//    @Date             :    24-8-1
//    @Email            :    445267987@qq.com
//    @Module           :    NFSecurity
//
// -------------------------------------------------------------------------

#include "NFSecurity.h"

#include <iostream>
#include <iomanip>
//#include <snappy/snappy.h>

// =========================================================================
// 懒加载方式实现静态常量，避免静态初始化顺序问题（Static Initialization Order Fiasco）
// C++11 保证局部静态变量的线程安全初始化
// =========================================================================

NFSecurity::NFSecurity()
{
	m_aes_encrypt = NULL;
	m_aes_decrypt = NULL;
	m_client_dh_pubKey = NULL;
	m_client_dh_priKey = NULL;
}

void NFSecurity::InitClient()
{
	Init(GetDhP(), GetDhG());
}

void NFSecurity::InitServer()
{
	Init(GetServerDhP(), GetServerDhG());
}

void NFSecurity::Init(const CryptoPP::Integer& publicKey, const CryptoPP::Integer& privateKey)
{
	memset(m_iv, 0, sizeof(m_iv));
	m_client_dh.AccessGroupParameters().Initialize(publicKey, privateKey);
	m_client_dh_pubKey = new CryptoPP::SecByteBlock(m_client_dh.PublicKeyLength());
	m_client_dh_priKey = new CryptoPP::SecByteBlock(m_client_dh.PrivateKeyLength());

	CryptoPP::AutoSeededRandomPool rnd;
	m_client_dh.GenerateKeyPair(rnd, m_client_dh_priKey->BytePtr(), m_client_dh_pubKey->BytePtr());

	dump_secbyteblock("m_client_dh_pubKey", m_client_dh_pubKey);
	dump_secbyteblock("m_client_dh_priKey", m_client_dh_priKey);
}

NFSecurity::~NFSecurity()
{
	if (likely(NULL != m_aes_encrypt))
	{
		delete m_aes_encrypt;
		m_aes_encrypt = NULL;
	}

	if (likely(NULL != m_aes_decrypt))
	{
		delete m_aes_decrypt;
		m_aes_decrypt = NULL;
	}

	if (likely(NULL != m_client_dh_pubKey))
	{
		delete m_client_dh_pubKey;
		m_client_dh_pubKey = NULL;
	}

	if (likely(NULL != m_client_dh_priKey))
	{
		delete m_client_dh_priKey;
		m_client_dh_priKey = NULL;
	}
}

// 传入对方的dh公钥，生成aes加密对象
bool NFSecurity::init_aes(const char* other_dhpubkey, size_t key_size)
{
	CryptoPP::SecByteBlock otherPubKey((const unsigned char *)other_dhpubkey, key_size);
	dump_secbyteblock("other_dhpubkey", &otherPubKey);

	bool                   ret = false;
	CryptoPP::SecByteBlock client_secretKey(m_client_dh.AgreedValueLength());
	// 生成加密秘钥
	ret = m_client_dh.Agree(client_secretKey, m_client_dh_priKey->BytePtr(), otherPubKey);

	if (unlikely(!ret))
	{
		return ret;
	}
	// dump
	dump_secbyteblock("client_secretKey", &client_secretKey);

	// 生成加解密的对象
	m_aes_encrypt = new CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption{
		client_secretKey.BytePtr(),
		CryptoPP::AES::DEFAULT_KEYLENGTH, m_iv
	};
	m_aes_decrypt = new CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption{
		client_secretKey.BytePtr(),
		CryptoPP::AES::DEFAULT_KEYLENGTH, m_iv
	};

	return ret;
}

// 加密
void NFSecurity::aes_encrypt(const std::string& plain_text, std::string& cipher_text)
{
	CryptoPP::StringSource(plain_text, true,
						   new CryptoPP::StreamTransformationFilter(*m_aes_encrypt, new CryptoPP::StringSink(cipher_text)));
}

// 解密
void NFSecurity::aes_decrypt(const std::string& cipher_text, std::string& plain_text)
{
	CryptoPP::StringSource(cipher_text, true,
						   new CryptoPP::StreamTransformationFilter(*m_aes_decrypt, new CryptoPP::StringSink(plain_text)));
}

void NFSecurity::aes_encrypt(const char* plain_text, size_t length, std::string& cipher_text)
{
	CryptoPP::StringSource((const CryptoPP::byte *)plain_text, length, true,
						   new CryptoPP::StreamTransformationFilter(*m_aes_encrypt, new CryptoPP::StringSink(cipher_text)));
}

// 解密
void NFSecurity::aes_decrypt(const char* cipher_text, size_t length, std::string& plain_text)
{
	CryptoPP::StringSource((const CryptoPP::byte *)cipher_text, length, true,
						   new CryptoPP::StreamTransformationFilter(*m_aes_decrypt, new CryptoPP::StringSink(plain_text)));
}

void NFSecurity::dump_secbyteblock(const std::string& name, CryptoPP::SecByteBlock* block)
{
	CryptoPP::Integer decode_n;
	decode_n.Decode(block->BytePtr(), block->SizeInBytes());
	std::setbase(10);
}

bool NFSecurity::package_compress_encrypt(proto_client2access::Proto_C2ACompressType compress_type,
										proto_client2access::Proto_C2AEncryptType  encrypt_type,
										const std::string&                         input,
										std::string&                               output)
{
	// 压缩
	std::string compress_data;
	if (compress_type == proto_client2access::E_SNAPPY)
	{
		//size_t compress_size = snappy::Compress( input.c_str(), input.size(), &compress_data );
		//if ( unlikely( 0 == compress_size ) ) {
		//    return false;
		//}
	}
	else if (compress_type == proto_client2access::E_GZIP)
	{
		return false;
	}
	else if (compress_type == proto_client2access::E_NO_COMPRESS)
	{
		compress_data.assign(input);
	}
	else
	{
		return false;
	}

	// 加密
	if (encrypt_type == proto_client2access::E_AES)
	{
		aes_encrypt(compress_data, output);
	}
	else if (encrypt_type == proto_client2access::E_3DES)
	{
		return false;
	}
	else if (encrypt_type == proto_client2access::E_NO_ENCRYPT)
	{
		output.assign(compress_data);
	}
	else
	{
		return false;
	}
	return true;
}

// =========================================================================
// 懒加载实现：静态常量通过局部静态变量返回
// 优点：
// 1. 避免静态初始化顺序问题（Static Initialization Order Fiasco）
// 2. C++11 保证局部静态变量的线程安全初始化
// 3. 只有在实际使用时才初始化，节省资源
// 4. 更容易调试，初始化发生在明确的调用点
// =========================================================================

/**
 * @brief 获取服务器端 DH 参数 P
 * @return 返回服务器端 DH 参数 P 的常量引用
 * @note 使用局部静态变量实现懒加载，线程安全（C++11+）
 */
const CryptoPP::Integer& NFSecurity::GetServerDhP()
{
	// C++11 保证局部静态变量的线程安全初始化
	static const CryptoPP::Integer server_dh_p(
		"0x8b79f180cbd3f282de92e8b8f2d092674ffda61f01ed961f8ef04a1b7a3709ff748c2abf6226cf0c4538e48838193da456e92ee53"
		"0ef7aa703e741585e475b26cd64fa97819181cef27de2449cd385c49c9b030f89873b5b7eaf063a788f00db3cb670c73846bc4f76af"
		"062d672bde8f29806b81548411ab48b99aebfd9c2d09" );
	return server_dh_p;
}

/**
 * @brief 获取服务器端 DH 参数 G
 * @return 返回服务器端 DH 参数 G 的常量引用
 * @note 使用局部静态变量实现懒加载，线程安全（C++11+）
 */
const CryptoPP::Integer& NFSecurity::GetServerDhG()
{
	// C++11 保证局部静态变量的线程安全初始化
	static const CryptoPP::Integer server_dh_g(
		"0x029843c81d0ea285c41a49b1a2f8e11a56a4b39040dfbc5ec040150c16f72f874152f9c44c659d86f7717b2425b62597e9a453b13"
		"da327a31cde2cced600915252d30262d1e54f4f864ace0e484f98abdbb37ebb0ba4106af5f0935b744677fa2f7f3826dcef3a158695"
		"6105ebea805d871f34c46c25bc30fc66b2db26cb0a93" );
	return server_dh_g;
}

/**
 * @brief 获取客户端 DH 参数 P
 * @return 返回客户端 DH 参数 P 的常量引用
 * @note 使用局部静态变量实现懒加载，线程安全（C++11+）
 */
const CryptoPP::Integer& NFSecurity::GetDhP()
{
	// C++11 保证局部静态变量的线程安全初始化
	static const CryptoPP::Integer dh_p("0x1F009FBAC60F5FF9FAB5A105FB2DB452C3FEDF669D50AF9055B357E6AB48181CE5CB89C8EBB1B3960820A359F3EFE486A26FFAB4605");
	return dh_p;
}

/**
 * @brief 获取客户端 DH 参数 G
 * @return 返回客户端 DH 参数 G 的常量引用
 * @note 使用局部静态变量实现懒加载，线程安全（C++11+）
 */
const CryptoPP::Integer& NFSecurity::GetDhG()
{
	// C++11 保证局部静态变量的线程安全初始化
	static const CryptoPP::Integer dh_g("3");
	return dh_g;
}
